package cn.xiaobai.loader;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.Objects;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
 * @Author yangdaji
 * @Date 2023/10/27
 * @PackageName cn.xiaobai.loader
 * @ClassName Launcher
 */
public abstract class Launcher {

    protected void launch(String[] args) throws Exception {
        JarFile jarFile = createArchive();
        Manifest manifest = jarFile.getManifest();
        Attributes mainAttributes = manifest.getMainAttributes();
        String startClass = mainAttributes.getValue("Start-Class");

        Class<?> manClass = getStartClass(jarFile, startClass);
        new MainMethodRunner(null, manClass, args).run();
    }

    private Class<?> getStartClass(JarFile jarFile, String startClass) throws IOException, ClassNotFoundException {
        Enumeration<JarEntry> entries = jarFile.entries();
        JarClassLoader jarClassLoader = new JarClassLoader(jarFile);
        while (entries.hasMoreElements()) {
            JarEntry jarEntry = entries.nextElement();
            String entryName = jarEntry.getName();
            String className = matchClassName(entryName);
            if (isNested(jarEntry) && Objects.equals(className, startClass)) {
                return jarClassLoader.findClass(entryName, className);
            }
        }
        return null;
    }

    protected final JarFile createArchive() throws Exception {
        Class<JarLauncher> jarLauncherClass = JarLauncher.class;
        ProtectionDomain protectionDomain = jarLauncherClass.getProtectionDomain();
        CodeSource codeSource = protectionDomain.getCodeSource();
        URL location = codeSource.getLocation();
        String path = location != null ? location.getFile() : null;
        if (path == null) {
            throw new IllegalStateException("无法确定源文档位置!");
        }

        File root = new File(path);
        if (!root.exists()) {
            throw new IllegalStateException("无法确定源文档位置: " + root);
        }
        return new JarFile(root);
    }

    protected abstract boolean isNested(JarEntry jarEntry);

    protected abstract String matchClassName(String name);

}
